/**
 * This class holds information about files in a corpus, words in a corpus, and the relationship
 * between the files and words in the corpus. 
 */
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;


public class FileIndex {
	private String[] corpusPaths;

	private GregorianCalendar time;

	private HashMap wordInstances;

	private ArrayList fileIndexInstances;

	private CorpusIndexRWFactory indexFactory;

	private String stopWordFile;

	private String variableBreaks;

	private int corpusTotalLines;

	private int corpusTotalChars;

	private int corpusTotalWords;

	private int corpusTotalFiles;

	/***************************************************************************
	 * Creates a new instance of a file index with the factory
	 * 
	 * @param indexFactory
	 *            The factory that will return index readers and index writers
	 *            from disk
	 */
	public FileIndex(CorpusIndexRWFactory indexFactory) {
		this.indexFactory = indexFactory;
		wordInstances = new HashMap();
		fileIndexInstances = new ArrayList();
		time = new GregorianCalendar();
		stopWordFile = null;
		variableBreaks = null;
		corpusTotalLines = 0;
		corpusTotalChars = 0;
		corpusTotalWords = 0;
		corpusTotalFiles = 0;
	}
	
	/**
	 * Added by ZMA on 11/5/06
	 *
	 */
	public void setCorpusStats() {
		setCorpusTotalFiles(corpusPaths.length);
		for (int i = 0; i < corpusTotalFiles; i++) {
			FileIndexInstance fii = (FileIndexInstance) fileIndexInstances.get(i);
			corpusTotalLines += fii.lineSize;
			corpusTotalChars += fii.charSize;
			corpusTotalWords += fii.wordSize;
		}
	}

	/**
	 * Sets the corresponding class variables that are obtained from the command
	 * line arguments
	 * 
	 * @param stopWordFile
	 *            The full pathname of the stop word file
	 * @param variableBreaks
	 *            Either the default variable breaks or the overridden variable
	 *            breaks
	 */
	public void setCommandLineArgumentsInfo(String stopWordFile,
			String variableBreaks) {
		this.stopWordFile = stopWordFile;
		this.variableBreaks = variableBreaks;
	}

	/**
	 * Returns the date/time this File Index was created at
	 * 
	 * @return
	 */
	public GregorianCalendar getTime() {
		return time;
	}

	/**
	 * Sets the "created time" of this index to a different value
	 * 
	 * @param timeFromDisk
	 *            number of milliseconds since 1970
	 */
	public void setTime(long timeFromDisk) {
		time.setTimeInMillis(timeFromDisk);
	}

	/***************************************************************************
	 * Builds a file index from an array of PhraseHistograms
	 * 
	 * @param histo
	 *            phrase histograms obtained by a Histo object
	 */
	public void buildFileIndex(PhraseHistogram[] histo) {
		corpusPaths = new String[histo.length];
		for (int i = 0; i < histo.length; i++) {
			corpusPaths[i] = histo[i].getFileName();
			FileIndexInstance fileIndexInstance = new FileIndexInstance(
					histo[i].getFileName());
			fileIndexInstance.setSize(histo[i].numLines, histo[i].numWords,
					histo[i].numChars);
			fileIndexInstances.add(fileIndexInstance);
			Iterator wordHistogramIterator = histo[i].getPhraseIterator();
			while (wordHistogramIterator.hasNext()) {
				PhraseEntry currPhraseEntry = (PhraseEntry) wordHistogramIterator
						.next();
				String currWord = currPhraseEntry.wordList.get(0).toString();
				WordIndexInstance wordInstance = (WordIndexInstance) wordInstances
						.get(currWord);
				if (wordInstance == null) {
					wordInstance = new WordIndexInstance(currWord);
					wordInstances.put(currWord, wordInstance);
				}
				Iterator lineNumberIterator = currPhraseEntry
						.getLineNumberIterator();
				while (lineNumberIterator.hasNext()) {
					wordInstance.addFileHit(fileIndexInstance,
							((Integer) lineNumberIterator.next()).intValue());
				}

			}
		}
	}

	/**
	 * Finds file/line number matches for a word
	 * 
	 * @param word
	 *            The word to search for
	 * @return An array of WordInFileIndexInstance objects. Each one holds
	 *         information about the file and the line numbers for that file
	 */
	public WordInFileIndexInstance[] findWord(String word) {
		WordIndexInstance currWord = (WordIndexInstance) wordInstances
				.get(word);
		if (currWord == null)
			return null;
		WordInFileIndexInstance[] result = new WordInFileIndexInstance[currWord.matchFiles
				.size()];
		Iterator iter = currWord.matchFiles.values().iterator();
		int i = 0;
		while (iter.hasNext()) {
			result[i] = (WordInFileIndexInstance) iter.next();
			i++;
		}
		return result;
	}

	/**
	 * Uses its factory to get a corpus index writer and calls the writer to
	 * write the index to memory
	 * 
	 * @param outfile
	 *            absolute or relative path name for the file to be written
	 * @throws AIMException
	 *             If the file cannot be written it throws an AIMException
	 */
	public void exportFile(String outfile) throws AIMException {
		CorpusIndexWriter writer = indexFactory.getWriter();
		writer.writeIndex(this, outfile);
	}

	public int getCorpusTotalLines() {
		return corpusTotalLines;
	}

	public void setCorpusTotalLines(int corpusTotalLines) {
		this.corpusTotalLines = corpusTotalLines;
	}

	public ArrayList getFileIndexInstances() {
		return fileIndexInstances;
	}

	public CorpusIndexRWFactory getIndexFactory() {
		return indexFactory;
	}

	public void setIndexFactory(CorpusIndexRWFactory indexFactory) {
		this.indexFactory = indexFactory;
	}

	public void setCorpusPaths(String[] corpusPaths) {
		this.corpusPaths = corpusPaths;
	}

	public void setCorpusTotalChars(int corpusTotalChars) {
		this.corpusTotalChars = corpusTotalChars;
	}

	public void setCorpusTotalFiles(int corpusTotalFiles) {
		this.corpusTotalFiles = corpusTotalFiles;
	}

	public void setCorpusTotalWords(int corpusTotalWords) {
		this.corpusTotalWords = corpusTotalWords;
	}

	public int getCorpusTotalFiles() {
		return corpusTotalFiles;
	}

	public String getVariableBreaks() {
		return variableBreaks;
	}

	public int getCorpusTotalChars() {
		return corpusTotalChars;
	}

	public int getCorpusTotalWords() {
		return corpusTotalWords;
	}

	public String getStopWordFile() {
		return stopWordFile;
	}

	public HashMap getWordInstances() {
		return wordInstances;
	}

	public String[] getCorpusPaths() {
		return corpusPaths;
	}
}
